const minimist = require('minimist'),
    fs = require('fs'),
    path = require('path'),
    _ = require('lodash'),
    uuid = require('uuid/v4'),
    low = require('lowdb'),
    sizeOf = require('image-size'),
    Memory = require('lowdb/adapters/Memory');

var args = minimist(process.argv.slice(2));
const legalExtNames = ['.jpeg', '.jpg', '.png', '.gif'];
const db = low(new Memory());
var requestExit = false;
var shuffle = !_.isUndefined(args.s || args.shuffle);
var selectCache = [];

db.set('images', []).write();

let timer = setInterval(() => {
    let cachedCount = db
        .get('images')
        .size()
        .value();
    if (selectCache.length < 3 && cachedCount > 0) {
        fillCache(3 - selectCache.length);
    }
}, 2000);

process.on('message', data => {
    switch (data.type) {
        case 'scan':
            db.set('images', []).write();
            _.remove(selectCache, () => true);
            scan(data.target);
            break;
        case 'select':
            selectOne();
            break;
        case 'shuffle':
            shuffle = data.sign;
            _.remove(selectCache, () => true);
            break;
        case 'exit':
            db.set('images', []).write();
            clearInterval(timer);
            process.exit(0);
            break;
    }
});

function scanImage(sPath) {
    if (!_.includes(legalExtNames, path.extname(sPath).toLowerCase())) return;
    db
        .get('images')
        .push({
            id: uuid(),
            full: sPath,
            name: path.basename(sPath),
            count: 0,
            width: 0,
            height: 0
        })
        .write();
}

function scan(sPath) {
    let pathForScan = [sPath];
    while (pathForScan.length > 0) {
        try {
            let scanPath = pathForScan.shift();
            let stat = fs.statSync(scanPath);
            if (stat.isDirectory()) {
                let subs = fs.readdirSync(scanPath);
                pathForScan = pathForScan.concat(subs.map(i => path.join(scanPath, i)));
            }
            if (stat.isFile()) scanImage(scanPath);
        } catch (err) {
            console.error(err.message);
            continue;
        }
    }
}

function fillCache(count = 3) {
    for (let i = 0; i < count; i++) {
        let minc = db
            .get('images')
            .minBy(i => i.count)
            .value();
        let minCount = minc.count;
        let mins = db.get('images').filter({ count: minCount });
        let index = shuffle ? _.random(mins.size().value() - 1) : 0;
        let selected = mins
            .sortBy(s => s.full)
            .nth(index)
            .value();
        if (!_.isUndefined(selected)) {
            if (!_.eq(selected.width, 0) && !_.eq(selected.height, 0)) {
                selectCache.push(
                    _.assign(selected, {
                        source: `file://${selected.full}`
                    })
                );
            } else {
                try {
                    let dimensions = sizeOf(selected.full);
                    selectCache.push(
                        _.assign(selected, {
                            source: `file://${selected.full}`,
                            width: dimensions.width,
                            height: dimensions.height
                        })
                    );
                    db
                        .get('images')
                        .find({ id: selected.id })
                        .assign({
                            width: dimensions.width,
                            height: dimensions.height
                        })
                        .write();
                } catch (err) {
                    console.error(err.message);
                    db
                        .get('images')
                        .remove({ id: selected.id })
                        .write();
                    continue;
                }
            }
            db
                .get('images')
                .find({ id: selected.id })
                .assign({ count: selected.count + 1 })
                .write();
        }
    }
}

function selectOne() {
    let firstOne = selectCache.shift();
    if (_.isEmpty(firstOne)) firstOne = null;
    process.send({ type: 'selected', content: firstOne });
}
